﻿#pragma once

#include "geom_base.h"

namespace CAGD
{

/**
 * 曲线基类.
 */
template <int Dim> class GeomCurveDim : public GeomBase
{
  public:
    /**
     * @brief 基本构造.
     * @see
     */
    GeomCurveDim()
    {
    }

    /**
     * @brief 取值函数.
     * @return
     * @param t
     * @see
     */
    BPntN<Dim> Value(double t) const
    {
        BPntN<Dim> P;
        D0(t, P);
        return P;
    }

    /**
     * @brief 切向函数.
     * @return
     * @param t
     * @see
     */
    BVecN<Dim> Deriv(double t) const
    {
        BPntN<Dim> P;
        BVecN<Dim> V;
        D1(t, P, V);
        return V;
    }

    /**
     * @brief 返回类型.
     * @return
     * @see
     */
    GeomType Type() const override
    {
        return GeomType::CURVE;
    }

    /**
     * @brief 曲线点均匀采样.
     * @return
     * @param curve
     * @param size
     * @see
     */
    static std::vector<BPnt> UniformPointSample(Handle(GeomCurveDim) curve, int size)
    {
        std::vector<BPnt> points;
        double dt = curve->LastParameter() - curve->FirstParameter();
        for (int i = 0; i < size; i++)
        {
            double t = curve->FirstParameter() + i * 1.0 / (size - 1) * dt;
            points.push_back(curve->Value(t));
        }
        return points;
    }

    /**
     * @brief 曲线法线均匀采样.
     * @return
     * @param curve
     * @param size
     * @see
     */
    static std::vector<BVec> UniformNormalSample(Handle(GeomCurveDim) curve, int size)
    {
        std::vector<BVec> normals;
        double dt = curve->LastParameter() - curve->FirstParameter();
        for (int i = 0; i < size; i++)
        {
            double t = curve->FirstParameter() + i * 1.0 / (size - 1) * dt;
            BPnt P;
            BVec V1, V2;
            curve->D2(t, P, V1, V2);
            normals.push_back(V2);
        }
        return normals;
    }

    /**
     * @brief 起始参数.
     * @return
     * @see
     */
    virtual double FirstParameter() const = 0;

    /**
     * @brief 终止参数.
     * @return
     * @see
     */
    virtual double LastParameter() const = 0;

    /**
     * @brief 获得 0 阶导数.
     * @param t
     * @param P
     * @see
     */
    virtual void D0(double t, BPntN<Dim> &P) const = 0;

    /**
     * @brief 获得 1 阶导数.
     * @param t
     * @param P
     * @param V1
     * @see
     */
    virtual void D1(double t, BPntN<Dim> &P, BVecN<Dim> &V1) const = 0;

    /**
     * @brief 获得 2 阶导数.
     * @param t
     * @param P
     * @param V1
     * @param V2
     * @see
     */
    virtual void D2(double t, BPntN<Dim> &P, BVecN<Dim> &V1, BVecN<Dim> &V2) const = 0;

    /**
     * @brief 获得 N 阶导数.
     * @param N
     * @param t
     * @param P
     * @param V
     * @see
     */
    virtual void DN(int N, double t, BPntN<Dim> &P, std::vector<BVecN<Dim>> &V) const = 0;

    /**
     * @brief 获得控制点引用.
     * @return
     * @see
     */
    virtual std::vector<BPntN<Dim> *> MakeReference() = 0;
};

using GeomCurve = GeomCurveDim<3>;
using Geom2dCurve = GeomCurveDim<2>;

} // namespace CAGD
